package __贪心算法

/*
https://leetcode.cn/problems/lemonade-change/

860. 柠檬水找零
在柠檬水摊上，每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品，
（按账单 bills 支付的顺序）一次购买一杯。

每位顾客只买一杯柠檬水，然后向你付 5 美元、10 美元或 20 美元。
你必须给每个顾客正确找零，也就是说净交易是每位顾客向你支付 5 美元。

示例 1：
输入：bills = [5,5,5,10,20]
输出：true
解释：
前 3 位顾客那里，我们按顺序收取 3 张 5 美元的钞票。
第 4 位顾客那里，我们收取一张 10 美元的钞票，并返还 5 美元。
第 5 位顾客那里，我们找还一张 10 美元的钞票和一张 5 美元的钞票。
由于所有客户都得到了正确的找零，所以我们输出 true。

示例 2：
输入：bills = [5,5,10,10,20]
输出：false
解释：
前 2 位顾客那里，我们按顺序收取 2 张 5 美元的钞票。
对于接下来的 2 位顾客，我们收取一张 10 美元的钞票，然后返还 5 美元。
对于最后一位顾客，我们无法退回 15 美元，因为我们现在只有两张 10 美元的钞票。
由于不是每位顾客都得到了正确的找零，所以答案是 false。

思路:
但仔细一琢磨就会发现，可供我们做判断的空间非常少！
只需要维护三种金额的数量，5，10和20。
有如下三种情况：
  - 情况一：账单是5，直接收下。
  - 情况二：账单是10，消耗一个5，增加一个10
  - 情况三：账单是20，优先消耗一个10和一个5，如果不够，再消耗三个5

此时大家就发现 情况一，情况二，都是固定策略，都不用我们来做分析了，而唯一不确定的其实在情况三。
而情况三逻辑也不复杂甚至感觉纯模拟就可以了，其实情况三这里是有贪心的。

账单是20的情况，为什么要优先消耗一个10和一个5呢？
因为美元10只能给账单20找零，而美元5可以给账单10和账单20找零，美元5更万能！
所以局部最优：遇到账单20，优先消耗美元10，完成本次找零。全局最优：完成全部账单的找零。
*/
func lemonadeChange(bills []int) bool {
	ten, five := 0, 0 //计算10,5面额钞票的数量

	for i := 0; i < len(bills); i++ { //遍历账单
		if bills[i] == 5 { //如果收到了5, 计数++即可
			five++
		} else if bills[i] == 10 { //如果收到了10, 只能用5找零, 判断5钞票是否为0即可  能找零, 就10++, 5--
			if five == 0 {
				return false
			}
			ten++
			five--
		} else { //否则就是收到了20, 20可以用10+5找零,也可用5+5+5找零, 优先使用10+5找零, 因为5能应付更多找零情况
			if ten >= 1 && five >= 1 {
				ten--
				five--
			} else if five >= 3 {
				five -= 3
			} else {
				return false
			}
		}
	}

	//如果数组遍历完毕, 都能满足找零条件, 那么就可以满足找零, 返回true
	return true
}
